package com.lyn.tencent_health_code.service;

import com.lyn.tencent_health_code.dao.BaseDao;
import com.lyn.tencent_health_code.dao.UserDao;
import com.lyn.tencent_health_code.database.User;
import com.lyn.tencent_health_code.utils.TextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * @author almost
 */
@Service
public class UserService implements BaseDao<User, String> {
    @Autowired
    private UserDao userDao;

    @Override
    public User save(User user) {
        if (TextUtils.isEmpty(user.getId())) {
            user.setId(UUID.randomUUID().toString().replace("-", ""));
        }
        if (user.getTime() == 0) {
            user.setTime(System.currentTimeMillis());
        }
        return userDao.save(user);
    }

    @Override
    public boolean deleteById(String id) {
        try {
            userDao.deleteById(id);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public User update(User user) {
        return userDao.saveAndFlush(user);
    }

    @Override
    public User findById(String id) {
        Optional<User> byId = userDao.findById(id);
        if (byId.isPresent()) {
            return byId.get();
        }
        return null;
    }

    @Override
    public User findByName(String name) {
        return userDao.findUserByUserName(name);
    }

    @Override
    public boolean findByNameExist(String name) {
        User user = userDao.findUserByUserName(name);
        return user != null;
    }

    @Override
    public List<User> findByPag(int page, int size) {
        Page<User> userPage = userDao.findAll(new Pageable() {
            @Override
            public int getPageNumber() {
                return page;
            }

            @Override
            public int getPageSize() {
                return size;
            }

            @Override
            public long getOffset() {
                return page * size - size;
            }

            @Override
            public Sort getSort() {
                return Sort.by(Sort.Direction.DESC, "time");
            }

            @Override
            public Pageable next() {
                return null;
            }

            @Override
            public Pageable previousOrFirst() {
                return null;
            }

            @Override
            public Pageable first() {
                return null;
            }

            @Override
            public Pageable withPage(int i) {
                return null;
            }

            @Override
            public boolean hasPrevious() {
                return false;
            }
        });
        List<User> userList = new ArrayList<>();
        Iterator<User> userIterator = userPage.iterator();
        while (userIterator.hasNext()) {
            User user = userIterator.next();
            userList.add(user);
        }

        return userList;
    }


    @Override
    public List<User> findByPag(int page, int size, int type) {

        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.equal(root.get("type"), type));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        Page<User> userPage = userDao.findAll(userSpecification, new Pageable() {
            @Override
            public int getPageNumber() {
                return page;
            }

            @Override
            public int getPageSize() {
                return size;
            }

            @Override
            public long getOffset() {
                return page * size - size;
            }

            @Override
            public Sort getSort() {
                return Sort.by(Sort.Direction.DESC, "time");
            }

            @Override
            public Pageable next() {
                return null;
            }

            @Override
            public Pageable previousOrFirst() {
                return null;
            }

            @Override
            public Pageable first() {
                return null;
            }

            @Override
            public Pageable withPage(int i) {
                return null;
            }

            @Override
            public boolean hasPrevious() {
                return false;
            }
        });
        List<User> userList = new ArrayList<>();
        Iterator<User> userIterator = userPage.iterator();
        while (userIterator.hasNext()) {
            User user = userIterator.next();
            userList.add(user);
        }

        return userList;
    }

    @Override
    public long findByPagCount( int type) {
        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.equal(root.get("type"), type));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        return userDao.count(userSpecification);
    }

    @Override
    public List<User> findByPag(int page, int size, String startTime, String endTime) {
        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.greaterThanOrEqualTo(root.get("time"), startTime));
                predicates.add(cb.lessThanOrEqualTo(root.get("time"),endTime));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        Page<User> userPage = userDao.findAll(userSpecification, new Pageable() {
            @Override
            public int getPageNumber() {
                return page;
            }

            @Override
            public int getPageSize() {
                return size;
            }

            @Override
            public long getOffset() {
                return page * size - size;
            }

            @Override
            public Sort getSort() {
                return Sort.by(Sort.Direction.DESC, "time");
            }

            @Override
            public Pageable next() {
                return null;
            }

            @Override
            public Pageable previousOrFirst() {
                return null;
            }

            @Override
            public Pageable first() {
                return null;
            }

            @Override
            public Pageable withPage(int i) {
                return null;
            }

            @Override
            public boolean hasPrevious() {
                return false;
            }
        });
        List<User> userList = new ArrayList<>();
        Iterator<User> userIterator = userPage.iterator();
        while (userIterator.hasNext()) {
            User user = userIterator.next();
            userList.add(user);
        }

        return userList;
    }

    @Override
    public long findByPagCount( String startTime, String endTime) {
        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.greaterThanOrEqualTo(root.get("time"), startTime));
                predicates.add(cb.lessThanOrEqualTo(root.get("time"),endTime));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        return userDao.count(userSpecification);
    }

    @Override
    public List<User> findByPag(int page, int size, int type, String startTime, String endTime) {
        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.greaterThanOrEqualTo(root.get("time"), startTime));
                predicates.add(cb.lessThanOrEqualTo(root.get("time"),endTime));
                predicates.add(cb.equal(root.get("type"),type));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        Page<User> userPage = userDao.findAll(userSpecification, new Pageable() {
            @Override
            public int getPageNumber() {
                return page;
            }

            @Override
            public int getPageSize() {
                return size;
            }

            @Override
            public long getOffset() {
                return page * size - size;
            }

            @Override
            public Sort getSort() {
                return Sort.by(Sort.Direction.DESC, "time");
            }

            @Override
            public Pageable next() {
                return null;
            }

            @Override
            public Pageable previousOrFirst() {
                return null;
            }

            @Override
            public Pageable first() {
                return null;
            }

            @Override
            public Pageable withPage(int i) {
                return null;
            }

            @Override
            public boolean hasPrevious() {
                return false;
            }
        });
        List<User> userList = new ArrayList<>();
        Iterator<User> userIterator = userPage.iterator();
        while (userIterator.hasNext()) {
            User user = userIterator.next();
            userList.add(user);
        }

        return userList;
    }

    @Override
    public long findByPagCount(int type, String startTime, String endTime) {
        Specification<User> userSpecification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.greaterThanOrEqualTo(root.get("time"), startTime));
                predicates.add(cb.lessThanOrEqualTo(root.get("time"),endTime));
                predicates.add(cb.equal(root.get("type"),type));
                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
        return userDao.count(userSpecification);
    }




    @Override
    public long count() {
        return userDao.count();
    }


}
